package cn.net.isir.controller.common;

import cn.net.isir.common.ResultObject;
import cn.net.isir.common.TokenManager;
import cn.net.isir.core.IgnoredTicket;
import cn.net.isir.core.RequestHolder;
import cn.net.isir.entity.FileUploadLog;
import cn.net.isir.service.FileUploadLogService;
import cn.net.isir.utils.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author liuxubo
 * @filename MultiMediaController.java
 * @package cn.net.isir.controller.miniprogram
 * @email lxb@isir.net.cn
 * @date 2018/08/28
 * @comment 文件上传下载类
 * @since 1.7
 */
@RestController
@RequestMapping(value = "/media")
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class, RuntimeException.class})
public class MultiMediaController {

    private Logger logger = Logger.getLogger(MultiMediaController.class);

    @Resource
    private FileUploadLogService fileUploadLogService;

    /**
     * 文件上传，支持多个文件
     *
     * @param files 文件name
     * @return result结果为200的时候是正常的，object是一个list，
     * 其中包含的每个对象包括一个resFileName和一个fileId
     */
    @IgnoredTicket
    @RequestMapping(method = RequestMethod.POST, value = "/upload")
    public ResultObject uploadFiles(@RequestParam("files") MultipartFile[] files,
                                    HttpServletRequest request, HttpServletResponse response) {
        Arrays.stream(files).forEach(i -> {
            logger.info(i.getName());
            logger.info(i.getSize());
        });
        ResultObject ro = new ResultObject();
        if (files.length == 0) {
            ro.setResult(500);
            ro.setMessage("未上传任何文件");
            return ro;
        }
        //获取项目根路径
        String path = RequestHolder.getSession().getServletContext().getRealPath("/");
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (MultipartFile multipartFile : files) {
            Map<String, Object> map = new HashMap<>();
            if (multipartFile != null && multipartFile.getSize() > 0) {
                String originalFilename = multipartFile.getOriginalFilename();
                originalFilename = new String(multipartFile.getOriginalFilename().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
                //获取原文件后缀
                String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
                String filename = "upload/files/" + System.currentTimeMillis() + new Random().nextInt(100) + "." + suffix;
                File targetFile = new File(path + filename);
                try {
                    if (!targetFile.getParentFile().exists()) {
                        if (!targetFile.mkdirs()) {
                            ro.setResult(500);
                            ro.setMessage("文件写入失败");
                            return ro;
                        }
                    }
                    multipartFile.transferTo(targetFile);
                } catch (IOException e) {
                    e.printStackTrace();
                    logger.info(e.getMessage());
                    logger.error(e);
                }
                FileUploadLog log = new FileUploadLog();
                log.setOldName(originalFilename);
                log.setNewName(filename.substring(filename.lastIndexOf("/")));
                log.setNewPath(path + filename);
                log.setSuffix(suffix);
                log.setUploadTime(new Date());
                try {
                    log.setUploadUserid(Integer.valueOf(TokenManager.getTokenId()));
                    log.setUserIdType(1);
                } catch (Exception ex2) {
                    logger.info("userid 获取失败");
                    log.setUploadUserid(null);
                    log.setUserIdType(null);
                }
                fileUploadLogService.insert(log);
                map.put("resFileName", originalFilename);
                map.put("fileId", log.getId());
                resultList.add(map);
            }
        }
        ro.setResult(200);
        ro.setMessage("success");
        ro.setObject(resultList);
        return ro;
    }

    /**
     * 文件上传，支持多个文件
     *
     * @param base64Dto 文件name
     * @return result结果为200的时候是正常的，object是一个list，
     * 其中包含的每个对象包括一个resFileName和一个fileId
     */
    @IgnoredTicket
    @RequestMapping(method = RequestMethod.POST, value = "/uploadByBase64")
    public ResultObject uploadFilesByBase64(@RequestBody Base64Dto base64Dto,
                                            HttpServletRequest request, HttpServletResponse response) {
        Base64Dto[] base64Dtos = new Base64Dto[]{base64Dto};
        Arrays.stream(base64Dtos).forEach(item -> {
            logger.info(item.getName());
            logger.info(item.getType());
            logger.info(item.getBase64().length());
        });
//        Arrays.stream(files).forEach(i -> {
//            logger.info(i.getName());
//            logger.info(i.getSize());
//        });
        ResultObject ro = new ResultObject();
        if (base64Dtos.length == 0) {
            ro.setResult(500);
            ro.setMessage("未上传任何文件");
            return ro;
        }
        //获取项目根路径
        String path = RequestHolder.getSession().getServletContext().getRealPath("/");
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Base64Dto dto : base64Dtos) {
            Map<String, Object> map = new HashMap<>();
            if (dto != null && StringUtils.isNotBlank(dto.getBase64())) {
                String originalFilename = dto.getName();
                originalFilename = new String(dto.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
                //获取原文件后缀
                String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
                String filename = "upload/files/" + System.currentTimeMillis() + new Random().nextInt(100) + "." + suffix;
                File targetFile = new File(path + filename);
                try {
                    if (!targetFile.getParentFile().exists()) {
                        if (!targetFile.mkdirs()) {
                            ro.setResult(500);
                            ro.setMessage("文件写入失败");
                            return ro;
                        }
                    }
                    //检查路径并创建
                    File dir = new File(path + "upload/files/");
                    if (!dir.exists()) {
                        dir.mkdirs();
                    }
                    //检查文件并创建
                    File file = new File(path + filename);
                    if (!file.exists()) {
                        file.createNewFile();
                    }
//                    multipartFile.transferTo(targetFile);
                    FileOutputStream fos = new FileOutputStream(file);
                    fos.write(dto.getBytes());
                    fos.flush();
                    fos.close();

                } catch (IOException e) {
                    e.printStackTrace();
                    logger.info(e.getMessage());
                    logger.error(e);
                }
                FileUploadLog log = new FileUploadLog();
                log.setOldName(originalFilename);
                log.setNewName(filename.substring(filename.lastIndexOf("/")));
                log.setNewPath(path + filename);
                log.setSuffix(suffix);
                log.setUploadTime(new Date());
                try {
                    log.setUploadUserid(Integer.valueOf(TokenManager.getTokenId()));
                    log.setUserIdType(1);
                } catch (Exception ex2) {
                    logger.info("userid 获取失败");
                    log.setUploadUserid(null);
                    log.setUserIdType(null);
                }
                fileUploadLogService.insert(log);
                map.put("resFileName", originalFilename);
                map.put("fileId", log.getId());
                resultList.add(map);
            }
        }
        ro.setResult(200);
        ro.setMessage("success");
        ro.setObject(resultList);
        return ro;
    }

    /**
     * 文件下载
     *
     * @param type     online：在线打开图片等，download：下载
     *                 注：online形式的，可以直接拼接在image的src中
     * @param fileId   文件id
     * @param response 输出流
     * @throws Exception exception
     *
     * url:http://ip:port/media/download/online/{fileId}/
     */
    @RequestMapping(method = RequestMethod.GET, value = "/download/{type}/{fileId}")
    public void download(@PathVariable String type, @PathVariable String fileId, HttpServletResponse response) throws Exception {
        byte[] buf = new byte[1024];
        int len;
        response.reset(); // 非常重要
//        String type = request.getParameter("type");
//        String fileId = request.getParameter("fileId");
        if (StringUtils.isBlank(fileId)) {
            response.sendError(400, "缺少fileId参数");
            return;
        }
        FileUploadLog log = new FileUploadLog();
        log.setId(fileId);
        log = fileUploadLogService.selectOne(log);
        if (log == null) {
            response.sendError(400, "未找到fileId对应的文件");
            return;
        }
        File f = new File(log.getNewPath());
        if (!f.exists()) {
            response.sendError(404, "File not found!");
            return;
        }
        BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));

        OutputStream out = response.getOutputStream();
        response.setCharacterEncoding("UTF-8");

        String fileName = new String(log.getOldName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);

        //如果不带有type，则仅返回文件名
        if (type == null) {
            response.setContentType("text/html;charset=UTF-8");
            String file = "{" + fileId + ":" + log.getOldName() + "}";
            out.write(file.getBytes(StandardCharsets.UTF_8));
            out.flush();
            out.close();
            return;
        }
        if ("online".equals(type)) { // 在线打开方式
            URL u = new URL("file:///" + log.getNewPath());
            response.setContentType(u.openConnection().getContentType());
            response.setHeader("Content-Disposition", "inline; filename=" + fileName);
            // 文件名应该编码成UTF-8
        }
        if ("download".equals(type)) { // 纯下载方式
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
        }
        while ((len = br.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        out.flush();
        out.close();
        br.close();
    }
}
